#ifdef __arm__
#ifndef __aarch64__
    .text
    .align  5
    //.p2align 5,,15
    .global ConvInt8
#ifndef __APPLE__
    .type   ConvInt8, %function
#endif

.macro INIT_ZERO
    // we could also use "vmov q12, 0" to initialize q12 by 0
    mov r8, #0
    vdup q12, r8
    vdup q13, r8
    vdup q14, r8
    vdup q15, r8
.endm

// void ConvInt8(input, weight, output, bias, step, depth, offset);
// r0: input, r1: weight, r2: output, r3, bias, r4: step, r5: depth, r6: offset
ConvInt8:
    // at return, clang generates "push {lr}, pop {pc}"" while gcc will generate "bx lr"
    // according to https://stackoverflow.com/questions/53625807
    // even if we jump to link register instead of saving it, we still have to save it in subroutine calls anyway
    // clang's rule seems more simple, though there are no subroutine calls here
    // r4-r8 and q4-q7 must be saved according to https://static.docs.arm.com/ihi0042/i/aapcs32.pdf
    push {r4-r8, lr}

    add r12, sp, #24
    ldm r12, {r4, r5,r6}

    vpush {q4-q7}

    INIT_ZERO

    ConvInt8LoopIc:
        // load input
        vld1.s8 {q0, q1}, [r0]!
        mov r7, r5
        vld1.s8 {q2, q3}, [r0]!
        ConvInt8LoopOc:
            // load weight
            vld1.s8 {q4, q5}, [r1]!
            vmull.s8 q8, d0, d8
            vmlal.s8 q8, d1, d9
            vpadal.s16 q12, q8
            vld1.s8 {q6, q7}, [r1]!
            vmull.s8 q9, d2, d10
            vmlal.s8 q9, d3, d11
            vpadal.s16 q12, q9
            vmull.s8 q10, d4, d12
            vmlal.s8 q10, d5, d13
            vpadal.s16 q12, q10
            vmull.s8 q11, d6, d14
            vmlal.s8 q11, d7, d15
            vld1.s8 {q4, q5}, [r1]!
            vpadal.s16 q12, q11
            
            vmull.s8 q8, d0, d8
            vmlal.s8 q8, d1, d9
            vpadal.s16 q13, q8
            vld1.s8 {q6, q7}, [r1]!
            vmull.s8 q9, d2, d10
            vmlal.s8 q9, d3, d11
            vpadal.s16 q13, q9
            vmull.s8 q10, d4, d12
            vmlal.s8 q10, d5, d13
            vpadal.s16 q13, q10
            vmull.s8 q11, d6, d14
            vmlal.s8 q11, d7, d15
            vld1.s8 {q4, q5}, [r1]!
            vpadal.s16 q13, q11

            vmull.s8 q8, d0, d8
            vmlal.s8 q8, d1, d9
            vpadal.s16 q14, q8
            vld1.s8 {q6, q7}, [r1]!
            vmull.s8 q9, d2, d10
            vmlal.s8 q9, d3, d11
            vpadal.s16 q14, q9
            vmull.s8 q10, d4, d12
            vmlal.s8 q10, d5, d13
            vpadal.s16 q14, q10
            vmull.s8 q11, d6, d14
            vmlal.s8 q11, d7, d15
            vld1.s8 {q4, q5}, [r1]!
            vpadal.s16 q14, q11

            vmull.s8 q8, d0, d8
            vmlal.s8 q8, d1, d9
            vpadal.s16 q15, q8
            vld1.s8 {q6, q7}, [r1]!
            vmull.s8 q9, d2, d10
            vmlal.s8 q9, d3, d11
            vpadal.s16 q15, q9
            vmull.s8 q10, d4, d12
            vmlal.s8 q10, d5, d13
            vpadal.s16 q15, q10
            vmull.s8 q11, d6, d14
            vmlal.s8 q11, d7, d15
            add r12, r1, #256
            pld [r12, #256]
            vpadal.s16 q15, q11

            subs r7, r7, #1
            beq ConvInt8LoopOc
        
        subs r4, r4, #1
        beq ConvInt8LoopIc
    
    vpadd.s32 d16, d24, d25
    vpadd.s32 d17, d26, d27
    vpadd.s32 d18, d28, d29
    vpadd.s32 d19, d30, d31
    vpadd.s32 d20, d16, d17
    vpadd.s32 d21, d18, d19

    vdup.s32 q11, r3
    vadd.s32 q10, q10, q11
    vst1.s32 {q10}, [r0]

    vpop {q4-q7}
    pop {r4, r5, r6, r7, r8, pc}

#endif
#endif
